// Copyright (c) 2005  INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of cgal-python; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; version 2.1 of the License.
// See the file LICENSE.LGPL distributed with cgal-python.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $Id: Py_Delaunay_triangulation_2.cpp 167 2007-11-02 15:36:54Z spion $
// $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal-python/trunk/cgal-python/bindings/Triangulations_2/Py_Delaunay_triangulation_2.cpp $
//
// Author(s)     : Naceur Meskini
//=========================================================================
// include ====================================================================
//#include <list>
#include <CGAL/basic.h>
#include <include/Kernels.h>
#include <include/iterator.h>

#include <CGAL/Delaunay_triangulation_2.h>

#include <CGAL/Alpha_shape_vertex_base_2.h>
#include <CGAL/Triangulation_hierarchy_vertex_base_2.h>
#include <CGAL/Triangulation_vertex_base_with_info_2.h>

#include <CGAL/Alpha_shape_face_base_2.h>
#include <CGAL/Delaunay_mesh_face_base_2.h>


#include "Py_Delaunay_Triangulation_2_doc.h"

#include <boost/python.hpp>
#include <boost/cstdint.hpp>


extern const char* Delaunay_2_docs[last];

using namespace boost::python;
namespace  {

	BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(is_valid_overloads_0_2, is_valid, 0, 2)
	BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(nearest_vertex_overloads_1_2, nearest_vertex, 1, 2)
	BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(insert_overloads_1_2, insert, 1, 2)

}// namespace 
template <class kernel,class Delaunay_triangulation,class Edge>
object dual(const Delaunay_triangulation& dt,const Edge& e)
{
	//three cases are possible:
	typedef typename kernel::Ray_2 			Ray_2;
	typedef typename kernel::Segment_2 		Segment_2;
	typedef typename kernel::Line_2 		Line_2;

	CGAL::Object o = dt.dual(e);
	Ray_2 r;
	Segment_2 s;
	Line_2 l;
	object obj;
	if( CGAL::assign(r,o) ) return object(r);
	else if(CGAL::assign(s,o)) return object(s);
	else {CGAL::assign(l,o);  return object(l);}	
	
}
template < class kernel,class Triangulation>
void py_insert(Triangulation& dt,boost::python::list pts)
{
	typedef typename kernel::Point_2 Point_2;
	for(int i = 0 ; i < pts.attr("__len__")() ; i++)
	{
		Point_2 P = boost::python::extract<Point_2>(pts[i]); 
		dt.insert(P);
	}
}

template <class Delaunay_triangulation_2,class Point_2>
boost::python::list py_get_conflicts(const Delaunay_triangulation_2& dt,Point_2 pt)
{
	boost::python::list result;
	typedef typename Delaunay_triangulation_2::Face_handle  Face_handle;
	std::list<Face_handle>  liste;
	dt.get_conflicts(pt, std::back_inserter(liste));
	typename std::list<Face_handle>::iterator iter;

	for(iter = liste.begin(); iter != liste.end(); iter++)
		result.append(*iter);
	
	return result;
}

template <class Delaunay_triangulation_2,class Point_2,class Edge>
boost::python::list py_get_boundary_of_conflicts(const Delaunay_triangulation_2& dt,Point_2 pt)
{
	boost::python::list result;
	std::list<Edge>  liste;
	dt.get_boundary_of_conflicts(pt, std::back_inserter(liste));
	typename std::list<Edge>::iterator iter;

	for(iter = liste.begin(); iter != liste.end(); iter++)
		result.append(*iter);

	return result;
}
//=========================
template < typename kernel>
void Py_Delaunay_triangulation_2()
{
	// three things must be fixed in order to insure the derivation in the python side.
	// -1: the vertex_base 
	// -2: the face_base
	// -3: the data_structure
	typedef CGAL::Alpha_shape_vertex_base_2<kernel> 	Avb;
	typedef CGAL::Triangulation_hierarchy_vertex_base_2<Avb> Hv; //this one is needed when the input data set is huge for the Alpha_shape_2,
																 // say more than 10.000 points,
	typedef CGAL::Triangulation_vertex_base_with_info_2<boost::python::object,kernel,Hv> 	Vb;

	typedef CGAL::Delaunay_mesh_face_base_2<kernel> 	Mf; 
	typedef CGAL::Alpha_shape_face_base_2<kernel,Mf> 	Af;

	typedef CGAL::Triangulation_data_structure_2<Vb,Af> Tds;

	typedef CGAL::Triangulation_2<kernel,Tds>   							Triangulation_2;
	typedef CGAL::Delaunay_triangulation_2<kernel,Tds>   					Delaunay_triangulation_2;

	typedef typename Delaunay_triangulation_2::Point_iterator 				Point_iterator;
	typedef typename Delaunay_triangulation_2::Finite_vertices_iterator 	Finite_vertices_iterator;
	typedef typename Delaunay_triangulation_2::All_vertices_iterator 		All_vertices_iterator;
	typedef typename Delaunay_triangulation_2::Finite_faces_iterator 		Finite_faces_iterator;
	typedef typename Delaunay_triangulation_2::All_faces_iterator 	    	All_faces_iterator;
	typedef typename Delaunay_triangulation_2::Face_handle 					Face_handle;
	typedef typename Delaunay_triangulation_2::Vertex_handle 				Vertex_handle;
	typedef typename Delaunay_triangulation_2::Edge 						Edge;
	typedef typename Delaunay_triangulation_2::Finite_edges_iterator		Finite_edges_iterator;
	typedef typename Delaunay_triangulation_2::All_edges_iterator			All_edges_iterator;
	typedef typename Triangulation_2::Locate_type 							Locate_type;
	typedef typename kernel::Point_2 										Point_2;
	typedef typename kernel::Segment_2 										Segment_2;
	typedef typename std::list<Face_handle>::iterator  						OutputItFaces;
	typedef typename std::list<Edge>::iterator  							OutputItEdges;

    class_< Delaunay_triangulation_2, bases< Triangulation_2 >  >("Delaunay_triangulation_2", Delaunay_2_docs[Delaunay_2_doc],init< optional< const kernel& > >())
        .def(init< const Delaunay_triangulation_2& >())
        .def("is_valid", &Delaunay_triangulation_2::is_valid, is_valid_overloads_0_2())
        .def("nearest_vertex", &Delaunay_triangulation_2::nearest_vertex,nearest_vertex_overloads_1_2())
       	.def("dual", (Point_2 (Delaunay_triangulation_2::*)(Face_handle) const)&Delaunay_triangulation_2::dual)
        .def("dual", &dual<kernel,Delaunay_triangulation_2,Edge>, Delaunay_2_docs[dual_doc])
       	.def("insert", (Vertex_handle (Delaunay_triangulation_2::*)(const Point_2&, Face_handle) )&Delaunay_triangulation_2::insert, insert_overloads_1_2())
        .def("insert", (Vertex_handle (Delaunay_triangulation_2::*)(const Point_2&, Locate_type, Face_handle, int) )&Delaunay_triangulation_2::insert)
        .def("insert", &py_insert<kernel,Delaunay_triangulation_2>, Delaunay_2_docs[insert_doc])
        .def("push_back", &Delaunay_triangulation_2::push_back, Delaunay_2_docs[push_back_doc])
        .def("remove", &Delaunay_triangulation_2::remove, Delaunay_2_docs[remove_doc])
	.def("get_conflicts",&py_get_conflicts<Delaunay_triangulation_2,Point_2>)
	.def("get_boundary_of_conflicts",&py_get_boundary_of_conflicts<Delaunay_triangulation_2,Point_2,Edge>)
	.def("side_of_oriented_circle",&Triangulation_2::side_of_oriented_circle,Delaunay_2_docs[side_of_oriented_circle_doc])
	;
}


void export_Delaunay_triangulation_2()
{
	Py_Delaunay_triangulation_2<K>();
}
